Terraform 0.15の変更点を調べた
TerraformのVersion 0.15がGAになって(2021/04/15)からだいぶ経ってしまいましたが、Webinarを視聴したり、実際に0.15を触ったりして何が変わったのか色々調べたのでレポートします。 (すべての変更点を網羅しているわけではないので悪しからず。)
0.14、1.0との互換性
Terraform Version 0.15は1つ前の0.14、そして今後リリースされる Version1.0と互換性があります。これはVersion 0.14の紹介でも説明されていましたね。Version間の移行(多くの場合Versionアップだと思いますが)が容易になります。
Remote State Data SourceのVersion間互換
- ~> 0.15.0
- ~> 0.14.0
- ~> 0.13.6
- ~> 0.12.30
上記Versionに当てはまるTerraformは、互いのRemote State Data Sourceにアクセスできます。今後リリースされる1.0.xまでのVersionについても同じ対応がされる予定です。既存の古いバージョンのTerraformと連携する必要がある場合でも、最新のバージョンのTerraformを使いやすくなりますね。
コンソールエクスペリエンスの統合
サポートしている全プラットフォームで一貫したコンソールエクスペリエンスを得られるようになりました。WindowsにてUTF-8とバーチャルコンソールをサポートしました。バーチャルコンソールに関しては、これまでのTerraformは、Windows独自の(=他プラットフォームと互換性のない)コンソールウインドウに対応するためのレイヤーを使用することで対応していました。ただしこの事により、進行状況インジケーターなど一部のターミナル機能が使えなくなっていました。Windows10のあるアップデート以降、他プラットフォームに似たバーチャルコンソールが導入されたので、バージョン0.15からは前述のレイヤーを使わないように修正が入りました。
※ Windowsわからないのでこのあたりの説明間違っているかもしれません。間違っている箇所あればご指摘いただければ幸いです。
Provider Sensitivity Graduates to Production
0.14でexperimental featureとして提供されていたprovider_sensitive_attrsがGAになりました。つまり、0.14ではterraformブロックにて明示的にこの機能を有効化する必要がありましたが、0.15からはその必要はなく、デフォルトの挙動になりました。
どういう機能か説明します。
0.14で変数の引数として、それ以前のバージョンでもOutputの引数としてsensitive
がありました。これは該当の変数やOutputの値をterraform plan
やterraform apply
などの出力時に隠すものです。例えば、Terraformのアウトプットを何らかのロギングシステムやVCS(バージョンコントールシステム)に記録している場合、この機能が役立つでしょう。(ただし、この機能を使ってもStateファイルに変数値が書き込まれる点は変わりませんので、依然としてStateファイルの扱いには気をつけましょう。)
そして、providerもそこで使われる引数値をsensitive
と定義することができます。例えばRDSインスタンスを作成する aws_db_instanceリソースです。password
引数はsensitive
と設定されています。つまりterraform plan
やterraform apply
などの出力時にはこのpassword
の値は隠蔽化されてます。
なのですが、もしこのpassword
値を参照している他の変数やOutputがあった場合、その値は隠蔽化されませんでした。
0.14ではこういった場合、experimental featureを有効化すれば、先のpassword
値を参照している他の変数やOutput値も隠蔽化されました。
0.15ではこういった場合、experimental featureを有効化する必要はありません。代わりにエラーになります。
以下のように、sensitive = true
を追加すると…
output password { value = aws_db_instance.default.password + sensitive = true }
まとめると、providerが設定したsensitive引数に関しても、あなたが設定したsensitiveな変数やOutputと同様な扱いをしてくれるようになったということです。
Sensitive/Nonsensitive Function
上記例でエラーを修正する別パターンとして、nonsensitive
Functionを使う方法もあります。これはその名の通り、明示的にsensitive設定を解除する関数です。
output password { + value = nonsensitive(aws_db_instance.default.password) - value = aws_db_instance.default.password }
真逆の働きをする sensitive
Functionもあります。
Providerの設定にconfiguration_aliases
追加
Module内でproviderのaliasを使う際の設定方法の変更です。(これまでそういった構成を経験したことがなかったので理解に手こずりました…)
例えば、2つのリージョンそれぞれに1つずつVPCを作成するようなModuleを作るとします。
0.14の場合
0.14でこういったModuleを作った場合、以下のようなコードになります。
provider "aws" { alias = "second" } resource "aws_vpc" "first" { cidr_block = "10.0.0.0/16" tags = { Name = "first" } } resource "aws_vpc" "second" { provider = aws.second cidr_block = "10.0.0.0/16" tags = { Name = "second" } }
最初の3行で、 aws providerのaliasを定義しているのがポイントです。
このModuleを呼び出す側のコード例は以下です。東京リージョンと大阪リージョンでVPCを作成します。
terraform { required_version = "~> 0.14.11" required_providers { aws = { source = "hashicorp/aws" version = "3.38.0" } } } provider "aws" { region = "ap-northeast-1" } provider "aws" { alias = "osaka" region = "ap-northeast-3" } module "vpc" { source = "./module/" providers = { aws.second = aws.osaka } }
最後のModuleブロックでprovidersブロックを定義して、alias=osakaのproviderを渡しています。 aliasのproviderはこのように明示的にModuleに渡す必要があります。一方デフォルトproviderはこのように書かなくてもModuleに自動的に継承されます。
0.15の場合
同じコードを0.15で実行(terraform apply
)してみましょう。Warningが出ました。
╷ │ Warning: Empty provider configuration blocks are not required │ │ on module/main.tf line 1: │ 27: provider "aws" { │ │ Remove the aws.second provider block from module.vpc. Add aws.second to the list of configuration_aliases for │ aws in required_providers to define the provider configuration name. ╵
はい。エラーメッセージに書かれているとおりですが、
- alias.secondのaws providerブロックが不要になりました。
- 代わりにterraformブロック内にrequired_providersブロックを定義し、そこの引数configuration_aliasesにalias.secondを書きます。
+terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "3.38.0" + configuration_aliases = [aws.second] + } + } +} -provider "aws" { - alias = "second" -} resource "aws_vpc" "first" { cidr_block = "10.0.0.0/16" tags = { Name = "first" } } resource "aws_vpc" "second" { provider = aws.second cidr_block = "10.0.0.0/16" tags = { Name = "second" } }
実行(terraform plan
やterraform apply
)前に一度terraform init
する必要があります。
これで先程のWarningを消すことができました。
この変更により、Module内で使われるProvider、またAliasのProviderがわかりやすくなります。特にModule作成者と使用者が異なる場合によりModuleを理解しやすく、使いやすくなるでしょう。
コアとプロバイダーのログレベルを分けて設定できるように
TF_LOG
環境変数に値TRACE
, DEBUG
, INFO
, WARN
, ERROR
を設定することで、Terraformのログを設定した値のレベルで出力できるようになります。0.15よりTerraformのコア部分が吐き出すログと、各プロバイダーが吐くログのレベルを別々に設定できるようになりました。それぞれTF_LOG_CORE
とTF_LOG_PROVIDER
という環境変数を使います。設定する値はTF_LOG
と同じくTRACE
, DEBUG
, INFO
, WARN
, ERROR
のいずれかです。
未宣言変数の使用が非推奨に
Terraform内で変数を使う場合、通常はvariable
ブロックで変数を宣言してから、任意の場所でその変数を参照します。
が、この変数宣言無しで変数を使うこともできます。変数用のファイルを読み込ませる場合です。(参考)
このような使用をした場合は、以下のような、variable
ブロックちゃんと書いてね、もしくは環境変数にしてね、というwarningが出るようになりました。
(という説明だったのですが、0.14.0で動作検証してもこのwarning出ました。。いつから追加されたのかよくわからないです…)
list() と map() 関数が tolist() と tomap()に置き換え
Version 0.12からlist()
と map()
関数はそれぞれ [ ... ]
と{ ... }
に置き換わりました。0.15からはこれらの関数を使うとエラーになります。
╷ │ Error: Error in function call │ │ on variables.tf line 3, in locals: │ 3: aa = list("a", "b", "c") │ │ Call to function "list" failed: the "list" function was deprecated in Terraform v0.12 and is no longer available; use tolist([ │ ... ]) syntax to write a literal list.
代わりにtolist()
とtomap()
を使いましょう。
- list("a", "b", "c") + tolist(["a", "b", "c"]) - map("a", 1, "b", 2) + tomap({ a = 1, b = 2 })
もしくは、多くの場合では関数を使わず単に [ ... ]
や{ ... }
を使うだけで十分です。
0.11スタイルの変数型指定廃止、ダブルクオートで囲む必要なし
variable "hoo" { type = "string" }
こういうコードを書くと以下エラーになります。
│ Error: Invalid quoted type constraints │ │ on variables.tf line 8, in variable "aaaa": │ 8: type = "string" │ │ Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed │ in a future version of Terraform. Remove the quotes around "string". ╵
ダブルクオートが不要になりました。
variable "hoo" { - type = "string" + type = string }
Apple M1対応はまだ
Webinarの中では、Providerも併せて対応しないと意味がないから…今各Providerに展開中だからStay Tuned!みたいな説明でした。
Azure Backend引数からarm_
prefixを削除
Azure Backendの引数のうちprefixとしてarm_
がついているものは以前より非推奨でしたが、0.15から完全に削除されました。今後はarm_
prefixを削除した引数に置き換える必要があります。
terraform plan
terraform apply
に -replace=
オプション追加
Version 0.15.2からです。-replace=
の引数値としてリソースのアドレス(terraform state list
で見れるやつ)を指定すると、そのリソースを置き換えるplan
やapply
になります。
terraform plan
terraform apply
に -destroy
オプション追加
Version 0.15.2からです。terraform apply -destroy
はterraform destory
のエイリアスです。terraform plan -destroy
はdestroyの実行計画のみみるオプションです。
terraform destroy
は今後terraform apply -destroy
に置き換わるのかな?と思いましたが、terraform destroy
を今後非推奨にする計画は今のところ無いそうです。
terraform外での変更を区別可能に
Version 0.15.4からです。terraform plan
terraform apply
の際に適用される差分が表示されますが、その差分が、Terraformのコードを最後のapply以降更新したから発生したものではなく、Terraform外でリソースを更新したから発生したものである場合、そのことがわかるような出力になります。
例えば、以下のようなVPCを作成するコードがあるとします。
resource "aws_vpc" "first" { cidr_block = "10.0.0.0/16" tags = { Name = "first" } }
これをterraform apply
してVPCを作成した後に、AWSのマネコンにて以下のようにVPC名を変えたとします。
その後再度 terraform plan
やterraform apply
すると以下のような出力になります。
横線で区切られるまでの前半部分が、Terraform外でリソース更新を検知したことを伝えています。
Note: Objects have changed outside of Terraform Terraform detected the following changes made outside of Terraform since the last "terraform apply": # module.vpc.aws_vpc.first has been changed ~ resource "aws_vpc" "first" { id = "vpc-0f483d0fdb450f1e3" ~ tags = { ~ "Name" = "first" -> "first-modified" } ~ tags_all = { ~ "Name" = "first" -> "first-modified" } # (14 unchanged attributes hidden) } Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes. ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: # module.vpc.aws_vpc.first will be updated in-place ~ resource "aws_vpc" "first" { id = "vpc-0f483d0fdb450f1e3" ~ tags = { ~ "Name" = "first-modified" -> "first" } ~ tags_all = { ~ "Name" = "first-modified" -> "first" } # (14 unchanged attributes hidden) } Plan: 0 to add, 1 to change, 0 to destroy.
これは嬉しい機能ですね!差分がコードの更新によって発生したものなのか、はたまたTerraform外で修正したから発生したものなのかの判断が容易になり、より自信をもってapplyできるようになります。
また、これに伴い、terraform apply
に -refresh-only
というオプションが追加されました。先程の例でこのオプションを使うと、以下のようになります。
% terraform apply -refresh-only module.vpc.aws_vpc.first: Refreshing state... [id=vpc-0f483d0fdb450f1e3] Note: Objects have changed outside of Terraform Terraform detected the following changes made outside of Terraform since the last "terraform apply": # module.vpc.aws_vpc.first has been changed ~ resource "aws_vpc" "first" { id = "vpc-0f483d0fdb450f1e3" ~ tags = { ~ "Name" = "first" -> "first-modified" } ~ tags_all = { ~ "Name" = "first" -> "first-modified" } # (14 unchanged attributes hidden) } This is a refresh-only plan, so Terraform will not take any actions to undo these. If you were expecting these changes then you can apply this plan to record the updated values in the Terraform state without changing any remote objects. Would you like to update the Terraform state to reflect these detected changes? Terraform will write these changes to the state without modifying any real infrastructure. There is no undo. Only 'yes' will be accepted to confirm. Enter a value:
はい。-refresh-only
という名前通り、Stateファイルの更新のみを行なうapplyです。リソースの更新は行ないません。従来から似たような機能として terraform refresh
というコマンドがありますが、こちらはただStateファイルを現在のリソースの状態に同期させるもので、どのような差分があったのか出力してくれませんし、また terraform apply -refresh-only
のように更新してよいかどうか確認もしてくれません。そのため今後は多くのケースでterraform apply -refresh-only
を使っていくほうが良いかと思います。